﻿using System;
using System.Drawing.Printing;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;

namespace YJKBatchPrinter
{
	public class MyPaperSize
	{
		public PaperSize GetPrintForm(string printerName, string paperName)
		{
			PaperSize result = null;
			foreach (object obj in new PrinterSettings
			{
				PrinterName = printerName
			}.PaperSizes)
			{
				PaperSize paperSize = (PaperSize)obj;
				if (paperSize.PaperName.ToLower() == paperName.ToLower())
				{
					result = paperSize;
					break;
				}
			}
			return result;
		}

		public void SetPrintForm(string printerName, string paperName, float width, float height)
		{
			if (PlatformID.Win32NT == Environment.OSVersion.Platform)
			{
				MyPaperSize.structPrinterDefaults structPrinterDefaults = default(MyPaperSize.structPrinterDefaults);
				structPrinterDefaults.pDatatype = null;
				structPrinterDefaults.pDevMode = IntPtr.Zero;
				structPrinterDefaults.DesiredAccess = 12;
				IntPtr zero = IntPtr.Zero;
				if (MyPaperSize.OpenPrinter(printerName, out zero, ref structPrinterDefaults))
				{
					try
					{
						MyPaperSize.structFormInfo1 structFormInfo = default(MyPaperSize.structFormInfo1);
						structFormInfo.Flags = 0;
						structFormInfo.pName = paperName;
						structFormInfo.Size.width = (int)((double)width * 100.0);
						structFormInfo.Size.height = (int)((double)height * 100.0);
						structFormInfo.ImageableArea.left = 0;
						structFormInfo.ImageableArea.right = structFormInfo.Size.width;
						structFormInfo.ImageableArea.top = 0;
						structFormInfo.ImageableArea.bottom = structFormInfo.Size.height;
						bool flag;
						if (this.GetPrintForm(printerName, paperName) != null)
						{
							flag = MyPaperSize.SetForm(zero, paperName, 1, ref structFormInfo);
						}
						else
						{
							this.AddCustomPaperSize(printerName, paperName, width, height);
							flag = true;
						}
						if (!flag)
						{
							StringBuilder stringBuilder = new StringBuilder();
							stringBuilder.AppendFormat("添加纸张{0}时发生错误!, 系统错误号: {1}", paperName, MyPaperSize.GetLastError());
							throw new ApplicationException(stringBuilder.ToString());
						}
					}
					finally
					{
						MyPaperSize.ClosePrinter(zero);
					}
				}
			}
		}

		public void AddCustomPaperSize(string printerName, string paperName, float width, float height)
		{
			if (PlatformID.Win32NT == Environment.OSVersion.Platform)
			{
				MyPaperSize.structPrinterDefaults structPrinterDefaults = default(MyPaperSize.structPrinterDefaults);
				structPrinterDefaults.pDatatype = null;
				structPrinterDefaults.pDevMode = IntPtr.Zero;
				structPrinterDefaults.DesiredAccess = 12;
				IntPtr zero = IntPtr.Zero;
				if (MyPaperSize.OpenPrinter(printerName, out zero, ref structPrinterDefaults))
				{
					try
					{
						MyPaperSize.structFormInfo1 structFormInfo = default(MyPaperSize.structFormInfo1);
						structFormInfo.Flags = 0;
						structFormInfo.pName = paperName;
						structFormInfo.Size.width = (int)((double)width * 100.0);
						structFormInfo.Size.height = (int)((double)height * 100.0);
						structFormInfo.ImageableArea.left = 0;
						structFormInfo.ImageableArea.right = structFormInfo.Size.width;
						structFormInfo.ImageableArea.top = 0;
						structFormInfo.ImageableArea.bottom = structFormInfo.Size.height;
						if (this.GetPrintForm(printerName, paperName) != null)
						{
							if (!MyPaperSize.SetForm(zero, paperName, 1, ref structFormInfo))
							{
								StringBuilder stringBuilder = new StringBuilder();
								stringBuilder.AppendFormat("设置纸张{0}时发生错误!, 系统错误号: {1}", paperName, MyPaperSize.GetLastError());
								throw new ApplicationException(stringBuilder.ToString());
							}
						}
						else if (!MyPaperSize.AddForm(zero, 1, ref structFormInfo))
						{
							StringBuilder stringBuilder2 = new StringBuilder();
							stringBuilder2.AppendFormat("添加纸张{0}时发生错误!, 系统错误号: {1}", paperName, MyPaperSize.GetLastError());
							throw new ApplicationException(stringBuilder2.ToString());
						}
						return;
					}
					finally
					{
						MyPaperSize.ClosePrinter(zero);
					}
				}
				StringBuilder stringBuilder3 = new StringBuilder();
				stringBuilder3.AppendFormat("打开打印机{0} 时出现异常!, 请检查打印机是否出错！", printerName, MyPaperSize.GetLastError());
				throw new ApplicationException(stringBuilder3.ToString());
			}
			MyPaperSize.structDevMode structDevMode = default(MyPaperSize.structDevMode);
			IntPtr intPtr = MyPaperSize.CreateDC(null, printerName, null, ref structDevMode);
			if (intPtr != IntPtr.Zero)
			{
				structDevMode.dmFields = 14;
				structDevMode.dmPaperSize = 256;
				structDevMode.dmPaperWidth = (short)((double)width * 2.54 * 10000.0);
				structDevMode.dmPaperLength = (short)((double)height * 2.54 * 10000.0);
				MyPaperSize.ResetDC(intPtr, ref structDevMode);
				MyPaperSize.DeleteDC(intPtr);
			}
		}

		[SuppressUnmanagedCodeSecurity]
		[DllImport("winspool.Drv", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
		internal static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPTStr)] string printerName, out IntPtr phPrinter, ref MyPaperSize.structPrinterDefaults pd);

		[SuppressUnmanagedCodeSecurity]
		[DllImport("winspool.Drv", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
		internal static extern bool ClosePrinter(IntPtr phPrinter);

		[SuppressUnmanagedCodeSecurity]
		[DllImport("winspool.Drv", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
		internal static extern bool AddForm(IntPtr phPrinter, [MarshalAs(UnmanagedType.I4)] int level, ref MyPaperSize.structFormInfo1 form);

		[SuppressUnmanagedCodeSecurity]
		[DllImport("winspool.Drv", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
		internal static extern bool DeleteForm(IntPtr phPrinter, [MarshalAs(UnmanagedType.LPTStr)] string pName);

		[SuppressUnmanagedCodeSecurity]
		[DllImport("winspool.Drv", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
		internal static extern bool SetForm(IntPtr phPrinter, [MarshalAs(UnmanagedType.LPTStr)] string pName, [MarshalAs(UnmanagedType.I4)] int level, ref MyPaperSize.structFormInfo1 form);

		[SuppressUnmanagedCodeSecurity]
		[DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)]
		internal static extern int GetLastError();

		[SuppressUnmanagedCodeSecurity]
		[DllImport("GDI32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
		internal static extern IntPtr CreateDC([MarshalAs(UnmanagedType.LPTStr)] string pDrive, [MarshalAs(UnmanagedType.LPTStr)] string pName, [MarshalAs(UnmanagedType.LPTStr)] string pOutput, ref MyPaperSize.structDevMode pDevMode);

		[SuppressUnmanagedCodeSecurity]
		[DllImport("GDI32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
		internal static extern IntPtr ResetDC(IntPtr hDC, ref MyPaperSize.structDevMode pDevMode);

		[SuppressUnmanagedCodeSecurity]
		[DllImport("GDI32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
		internal static extern bool DeleteDC(IntPtr hDC);

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		internal struct structPrinterDefaults
		{
			[MarshalAs(UnmanagedType.LPTStr)]
			public string pDatatype;

			public IntPtr pDevMode;

			[MarshalAs(UnmanagedType.I4)]
			public int DesiredAccess;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		internal struct structSize
		{
			public int width;

			public int height;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		internal struct structRect
		{
			public int left;

			public int top;

			public int right;

			public int bottom;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		internal struct structFormInfo1
		{
			[MarshalAs(UnmanagedType.I4)]
			public int Flags;

			[MarshalAs(UnmanagedType.LPTStr)]
			public string pName;

			public MyPaperSize.structSize Size;

			public MyPaperSize.structRect ImageableArea;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		internal struct structDevMode
		{
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
			public string dmDeviceName;

			[MarshalAs(UnmanagedType.U2)]
			public short dmSpecVersion;

			[MarshalAs(UnmanagedType.U2)]
			public short dmDriverVersion;

			[MarshalAs(UnmanagedType.U2)]
			public short dmSize;

			[MarshalAs(UnmanagedType.U2)]
			public short dmDriverExtra;

			[MarshalAs(UnmanagedType.U4)]
			public int dmFields;

			[MarshalAs(UnmanagedType.I2)]
			public short dmOrientation;

			[MarshalAs(UnmanagedType.I2)]
			public short dmPaperSize;

			[MarshalAs(UnmanagedType.I2)]
			public short dmPaperLength;

			[MarshalAs(UnmanagedType.I2)]
			public short dmPaperWidth;

			[MarshalAs(UnmanagedType.I2)]
			public short dmScale;

			[MarshalAs(UnmanagedType.I2)]
			public short dmCopies;

			[MarshalAs(UnmanagedType.I2)]
			public short dmDefaultSource;

			[MarshalAs(UnmanagedType.I2)]
			public short dmPrintQuality;

			[MarshalAs(UnmanagedType.I2)]
			public short dmColor;

			[MarshalAs(UnmanagedType.I2)]
			public short dmDuplex;

			[MarshalAs(UnmanagedType.I2)]
			public short dmYResolution;

			[MarshalAs(UnmanagedType.I2)]
			public short dmTTOption;

			[MarshalAs(UnmanagedType.I2)]
			public short dmCollate;

			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
			public string dmFormName;

			[MarshalAs(UnmanagedType.U2)]
			public short dmLogPixels;

			[MarshalAs(UnmanagedType.U4)]
			public int dmBitsPerPel;

			[MarshalAs(UnmanagedType.U4)]
			public int dmPelsWidth;

			[MarshalAs(UnmanagedType.U4)]
			public int dmPelsHeight;

			[MarshalAs(UnmanagedType.U4)]
			public int dmNup;

			[MarshalAs(UnmanagedType.U4)]
			public int dmDisplayFrequency;

			[MarshalAs(UnmanagedType.U4)]
			public int dmICMMethod;

			[MarshalAs(UnmanagedType.U4)]
			public int dmICMIntent;

			[MarshalAs(UnmanagedType.U4)]
			public int dmMediaType;

			[MarshalAs(UnmanagedType.U4)]
			public int dmDitherType;

			[MarshalAs(UnmanagedType.U4)]
			public int dmReserved1;

			[MarshalAs(UnmanagedType.U4)]
			public int dmReserved2;
		}
	}
}
